package com.colorlight.cloud.gateway.api.message.interceptor.trans.impl;

import com.colorlight.cloud.gateway.api.exception.ReflexException;
import com.colorlight.cloud.gateway.api.message.constraint.basics.ienum.EnumTrans;
import com.colorlight.cloud.gateway.api.message.constraint.basics.object.Trans;
import com.colorlight.cloud.gateway.api.message.interceptor.trans.TransToProtoInterceptor;
import com.colorlight.cloud.gateway.api.message.utils.BaseType;
import com.google.protobuf.Message;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.*;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 名为collection 实际为List<Object>
 * 如果有其他需要拦截 需要加入 目前只支持单层List<object> 不支持 嵌套 List<List<object>>
 *
 * @author Demon
 * @date 18/12/2023  下午5:46
 */
@Slf4j
public class CollectionTransToProtoInterceptor implements TransToProtoInterceptor {
	
	private final InterAttributeProcess interEnumProcess = new InterEnumProcess();
	private final InterAttributeProcess interTransProcess = new InterTransProcess();
	private final InterAttributeProcess interBaseProcess = new InterBaseProcess();
	
	@Override
	public Boolean isInterceptor(Class<?> aClass) {
		return List.class.isAssignableFrom(aClass);
	}
	
	@Override
	public String getMethodName(String name) {
		if (Objects.isNull(name) || name.length() == 0) {
			throw new ReflexException("sdk转化方法名异常");
		}
		return "addAll" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
	}
	
	@Override
	public void addAttribute(Message.Builder builder, Object value, Class<?> inputClass, String methodName) {
		/**
		 * 获取方法
		 * */
		Method method = null;
		try {
			/**
			 * 这里强依赖了protobuf转的对象 所有集合类型均为Iterable
			 * */
			method = builder.getClass().getMethod(methodName, Iterable.class);
		} catch (NoSuchMethodException e) {
			log.error("", e);
		}
		if (method == null) {
			throw new ReflexException("获取方法失败");
		}
		/**
		 * 多个类型：
		 *  与起始入参相同
		 *  1.基本类型
		 *  2.枚举类型
		 *  3.封装类型
		 * */
		Iterable<?> collect = invoke(inputClass).process(value);
		// 方法调用
		try {
			method.invoke(builder, collect);
		} catch (IllegalAccessException | InvocationTargetException e) {
			log.error("", e);
		}
	}
	
	@Override
	public Class<?> getInputClass(Field field) {
		return collectionInternalType(field);
	}
	
	/**
	 * 集合处理 集集合类得处理
	 *
	 * @param field 实际属性对象
	 * @return 目标类型集合得内置类型 单层集合
	 * @author Demon
	 * @date 18/12/2023/下午2:34
	 */
	private Class<?> collectionInternalType(Field field) {
		Type genericType = field.getGenericType();
		if (genericType instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) genericType;
			Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
			if (actualTypeArguments.length > 0 && actualTypeArguments[0] instanceof Class) {
				return (Class<?>) actualTypeArguments[0];
			}
		}
		throw new ReflexException("");
	}
	
	private InterAttributeProcess invoke(Class<?> aClass) {
		
		if (Trans.class.isAssignableFrom(aClass)) {
			return interTransProcess;
		}
		if (BaseType.isContains(aClass)) {
			return interBaseProcess;
		}
		if (EnumTrans.class.isAssignableFrom(aClass) && EnumTrans.class.isAssignableFrom(aClass)) {
			return interEnumProcess;
		}
		throw new ReflexException("无法转化的Collection类型");
	}
	
	private static class InterEnumProcess implements InterAttributeProcess {
		@Override
		public Iterable<?> process(Object o) {
			List<? extends EnumTrans<?, ?>> trans = (List<? extends EnumTrans<?, ?>>) o;
			return trans.stream().map(EnumTrans::toProto).collect(Collectors.toList());
		}
	}
	
	private static class InterBaseProcess implements InterAttributeProcess {
		@Override
		public Iterable<?> process(Object o) {
			return (List<?>) o;
		}
	}
	
	private static class InterTransProcess implements InterAttributeProcess {
		@Override
		public Iterable<?> process(Object o) {
			List<? extends Trans<?, ?>> trans = (List<? extends Trans<?, ?>>) o;
			return trans.stream().map(Trans::toProto).collect(Collectors.toList());
		}
	}
	
	@FunctionalInterface
	interface InterAttributeProcess {
		/**
		 * 参数转化器
		 *
		 * @param o 实际属性
		 * @return 几集合参数
		 * @author Demon
		 * @date 21/12/2023/上午9:00
		 */
		Iterable<?> process(Object o);
	}
}

